package cn.tonyandmoney.voicenotes.wav.ui

import android.annotation.SuppressLint
import android.media.MediaPlayer
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.widget.SeekBar
import android.widget.TextView
import cn.tonyandmoney.voicenotes.R
import cn.tonyandmoney.voicenotes.exception.BizException
import cn.tonyandmoney.voicenotes.greendao.gen.NoteRecordDao
import cn.tonyandmoney.voicenotes.greendao.gen.TNoteDao
import cn.tonyandmoney.voicenotes.greendao.utils.GreenDaoHelper
import cn.tonyandmoney.voicenotes.notes.config.Constants
import cn.tonyandmoney.voicenotes.notes.entity.NoteRecord
import cn.tonyandmoney.voicenotes.notes.entity.TNote
import cn.tonyandmoney.voicenotes.notes.entity.TRecord
import cn.tonyandmoney.voicenotes.ui.listeners.SimpleSeekBarChangeListener
import cn.tonyandmoney.voicenotes.utils.DateUtils
import cn.tonyandmoney.voicenotes.wav.utils.AudioEditUtil
import com.afollestad.materialdialogs.MaterialDialog
import com.dhh.rxlifecycle2.RxLifecycle
import com.zlzsy.app.base.ui.BaseActivity
import io.reactivex.Observable
import io.reactivex.ObservableSource
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import kotlinx.android.synthetic.main.activity_audio_player_layout.*
import org.jetbrains.anko.*
import java.io.File
import java.text.SimpleDateFormat
import java.util.*
import java.util.concurrent.TimeUnit

/**
 * 音频文件的播放
 */
class AudioPlayerActivity : BaseActivity(), MediaPlayer.OnPreparedListener, AnkoLogger,
        MediaPlayer.OnCompletionListener, SeekBar.OnSeekBarChangeListener {

    private val fileDao = GreenDaoHelper.session().tRecordDao
    private val noteRecordDao = GreenDaoHelper.session().noteRecordDao
    private val noteDao = GreenDaoHelper.session().tNoteDao
    private lateinit var mRecord: TRecord
    private val player = MediaPlayer()
    private var mNote: TNote? = null


    override fun initView() {
        supportActionBar?.setDisplayHomeAsUpEnabled(true)
        setContentView(R.layout.activity_audio_player_layout)
        btn_play.isEnabled = false
        btn_pause.isEnabled = false
        btn_stop.isEnabled = false

        btn_play.setOnClickListener {
            player.start()
            btn_play.isEnabled = false
            btn_stop.isEnabled = true
            btn_pause.isEnabled = true
        }
        btn_stop.setOnClickListener {
            player.pause()
            player.seekTo(0)
            btn_play.isEnabled = true
        }
        btn_pause.setOnClickListener {
            player.pause()
            btn_play.isEnabled = true
        }
        seekBar.isEnabled = false
        seekBar.setOnSeekBarChangeListener(this)

        Observable.interval(1, TimeUnit.SECONDS)
                .flatMap { ObservableSource<Int> { it.onNext(player.currentPosition) } }
                .observeOn(Schedulers.newThread())
                .unsubscribeOn(Schedulers.newThread())
                .compose(RxLifecycle.with(this).bindOnDestroy())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe { seekBar.progress = it }
    }

    @SuppressLint("SetTextI18n")
    override fun initData(savedInstanceState: Bundle?) {
        showLoadingDialog()
        val id = intent.getLongExtra("id", -1)
        if (id == -1L) {
            finish()
            return
        }
        mRecord = fileDao.load(id)
        info("file: ${mRecord.path}")
        visualizer.startListening()
        player.setOnPreparedListener(this)
        player.setOnCompletionListener(this)
        player.setDataSource(mRecord.path)
        player.prepareAsync()

        val nRecord = noteRecordDao.queryBuilder()
                .where(NoteRecordDao.Properties.RecordId.eq(id))
                .list()
                .firstOrNull()
        if (nRecord != null) {
            mNote = noteDao.queryBuilder()
                    .where(TNoteDao.Properties.Id.eq(nRecord.noteId))
                    .list()
                    .firstOrNull()
        }
        if (mNote != null) {
            note.text = "名称：${mNote!!.name}\n"
            note.append("类型：${mNote!!.type}\n")
            note.append("时间：${mNote!!.addTime ?: "无"}\n")
            note.append("备注：${mNote!!.memo}")
        }
        hideLoadingDialog()
    }

    override fun onPrepared(mp: MediaPlayer) {
        info("onPrepared->${mp.duration}")
        btn_play.isEnabled = true
        seekBar.isEnabled = true
        seekBar.max = mp.duration
        totalLength.text = lengthFormatter(seekBar.max)

    }

    override fun onCompletion(mp: MediaPlayer) {
        btn_play.isEnabled = true
    }

    override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
        curProgress.text = lengthFormatter(progress)
    }

    override fun onStartTrackingTouch(seekBar: SeekBar) {

    }

    private fun lengthFormatter(length: Int): String {
        val formatter = SimpleDateFormat("mm:ss", Locale.CANADA)
        return formatter.format(length)
    }


    /**
     * 拖动改变播放进度
     */
    override fun onStopTrackingTouch(seekBar: SeekBar) {
        val progress = seekBar.progress
        player.seekTo(progress)
    }

    private fun toCut(start: Int, end: Int) {
        if (start >= end) {
            longToast("开始时间不能大于截止时间。")
            return
        }
        Single.create<TRecord> {
            val srcFile = File(mRecord.path)
            val fileName = srcFile.name
            val outParent = File(Constants.sCutPath)
            if (!outParent.exists()) outParent.mkdirs()
            val outPath = Constants.sCutPath + "/" + DateUtils.toDDHHMM() + "_" + fileName
            AudioEditUtil.cutAudio(mRecord, outPath, start.toFloat(), end.toFloat())
            val cutRecord = TRecord()
            cutRecord.content = mRecord.content + "_副本_" + DateUtils.toDDHHMM()
            cutRecord.path = outPath
            cutRecord.duration = (end - start).toLong()
            cutRecord.id = fileDao.insert(cutRecord)
            noteRecordDao.insert(NoteRecord(mNote!!.id, cutRecord.id))
            it.onSuccess(cutRecord)
        }.subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe({ cutSuccess(it) }, { cutError(it) })

    }

    private fun cutSuccess(record: TRecord) {
        MaterialDialog.Builder(this)
                .title("提示")
                .content("剪切文件已保存到文件：\n${record.path}")
                .positiveText("确定")
                .show()
    }

    private fun cutError(throwable: Throwable) {
        error("cutError", throwable)
        val errMsg =
                if (throwable is BizException) {
                    throwable.message
                } else "剪切失败，请重试。"

        MaterialDialog.Builder(this)
                .title("错误")
                .content(errMsg)
                .positiveText("确定")
                .show()
    }

    private fun cutDialog() {
        val view = View.inflate(this, R.layout.dialog_audio_cut_layout, null)
        val startSeekBar = view.findViewById<SeekBar>(R.id.cutStart)
        val endSeekBar = view.find<SeekBar>(R.id.cutEnd)
        val startTextView = view.find<TextView>(R.id.date_start)
        val endTextView = view.find<TextView>(R.id.date_end)
        startSeekBar.max = seekBar.max
        endSeekBar.max = seekBar.max
        var start = 0
        var end = 0
        val listener = SimpleSeekBarChangeListener({ seekBar, progress ->
            if (seekBar == startSeekBar) {
                start = progress
                startTextView.text = DateUtils.formatter(progress.toLong(), "mm:ss")
            } else {
                end = progress
                endTextView.text = DateUtils.formatter(progress.toLong(), "mm:ss")
            }
        })
        startSeekBar.setOnSeekBarChangeListener(listener)
        endSeekBar.setOnSeekBarChangeListener(listener)
        MaterialDialog.Builder(this)
                .title("请输入裁剪信息")
                .customView(view, false)
                .positiveText("确定")
                .negativeText("取消")
                .onPositive { _, _ ->
                    toCut(start, end)
                }
                .show()
    }


    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        if (item.itemId == R.id.action_cut) {
            cutDialog()
            return true
        } else if (item.itemId == R.id.action_joint) {
            startActivity<AudioJointActivity>("id" to mRecord.id, "noteId" to mNote!!.id)
            return true
        }
        return super.onOptionsItemSelected(item)
    }

    override fun onCreateOptionsMenu(menu: Menu): Boolean {
        menuInflater.inflate(R.menu.audio_menu, menu)
        return true
    }


    override fun onDestroy() {
        super.onDestroy()
        if (player.isPlaying)
            player.stop()
        player.release()
    }

}